import { ShaderMaterial, MeshBasicMaterial, Layers, Vector2 } from 'three'
import { OutputPass ,
  RenderPass,
  ShaderPass,
  UnrealBloomPass,
  EffectComposer
} from 'three/examples/jsm/Addons'
import { shallowRef, watch } from 'vue'

// 定义辉光场景的层id
export const BLOOM_SCENE = 1
export const useUnrealBloom = (renderer, scene, camera) => {
  // 创建bloom场景
  const bloomLayer = new Layers()
  bloomLayer.set(BLOOM_SCENE)

  // Bloom效果参数配置
  const params = {
    threshold: 0, // 产生泛光的光照强度阈值
    strength: 1, // 泛光的强度
    radius: 0.5, // 泛光散发的半径
    exposure: 1 // 曝光度
  }

  // 黑色材质，用于隐藏不需要辉光的对象
  const darkMaterial = new MeshBasicMaterial({
    color: 0x000000
  })
  // 存储原始材质的对象
  const materials = {}
  // 渲染通道
  const renderScene = shallowRef(null)

  // bloom效果合成器
  const bloomComposer = shallowRef(null)
  // 最终效果合成器
  const finalComposer = shallowRef(null)

  // 初始化bloom合成器
  const initBloomComposer = () => {
    const { clientWidth, clientHeight } = renderer.value.domElement

    // 创建UnrealBloomPass
    const bloomPass = new UnrealBloomPass(
      new Vector2(clientWidth, clientHeight), // 泛光所覆盖的场景大小，是Vector2类型的向量
      1.5, // 泛光的强度，值越大明亮的区域越亮，较暗区域变亮的范围越广
      0.4, // 泛光散发的半径
      0.85 // 产生泛光的光照强度阈值，如果照在物体上的光照强度大于该值就会产生泛光
    )

    bloomPass.threshold = params.threshold
    bloomPass.strength = params.strength
    bloomPass.radius = params.radius

    // 创建效果合成器
    bloomComposer.value = new EffectComposer(renderer.value)
    // 设置不直接渲染到屏幕
    bloomComposer.value.renderToScreen = false
    // 添加渲染通道和bloom通道
    bloomComposer.value.addPass(renderScene.value)
    bloomComposer.value.addPass(bloomPass)
  }

  // 初始化最终合成器
  const initFinalComposer = () => {
    // 创建混合着色器通道，用于将原始场景和bloom效果混合
    const mixPass = new ShaderPass(
      new ShaderMaterial({
        uniforms: {
          baseTexture: { value: null },
          bloomTexture: { value: bloomComposer.value.renderTarget2.texture }
        },
        vertexShader: `
          varying vec2 vUv;
  
          void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
          }
        `,
        // 片段着色器，将原始纹理和bloom纹理混合
        fragmentShader: `
          uniform sampler2D baseTexture;
          uniform sampler2D bloomTexture;
  
          varying vec2 vUv;
  
          void main() {
            gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );
          }
        `,
        defines: {}
      }),
      'baseTexture'
    )
    mixPass.needsSwap = true

    const outputPass = new OutputPass()

    // 创建最终效果合成器
    finalComposer.value = new EffectComposer(renderer.value)
    // 添加渲染通道和混合通道
    finalComposer.value.addPass(renderScene.value)
    finalComposer.value.addPass(mixPass)
    finalComposer.value.addPass(outputPass)
  }

  // 将非bloom对象变暗
  const darkenNonBloomed = (obj) => {
    // 如果是网格对象且不在bloom层中
    if (obj.isMesh && bloomLayer.test(obj.layers) === false) {
      // 保存原始材质
      materials[obj.uuid] = obj.material
      obj.material = darkMaterial
    }
  }

  // 恢复对象的原始材质
  const restoreMaterial = (obj) => {
    if (materials[obj.uuid]) {
      // 恢复原始材质
      obj.material = materials[obj.uuid]
      delete materials[obj.uuid]
    }
  }

  // 更新unreal bloom效果
  const unrealBloomUpdate = () => {
    // 遍历场景，将非辉光对象变暗
    scene.value.traverse(darkenNonBloomed)
    // 渲染辉光效果
    bloomComposer.value.render()
    // 恢复材质
    scene.value.traverse(restoreMaterial)
    // 最终合成渲染
    finalComposer.value.render()
  }

  const init = () => {
    // 创建渲染通道
    renderScene.value = new RenderPass(scene.value, camera.value)
    initBloomComposer()
    initFinalComposer()
  }

  watch(
    () => renderer,
    () => {
      init()
    },
    { deep: true }
  )

  return {
    bloomComposer,
    finalComposer,
    unrealBloomUpdate
  }
}
